home *** CD-ROM | disk | FTP | other *** search
- /* LogManager.c */
- /*
- * LogManager.c
- * Copyright © 1993 Apple Computer Inc. All rights reserved.
- *
- * These functions manage a logging display for error messages and other text.
- * The log is implemented as a ListManager list that can hold nLogItems. This
- * module is intentionally more-or-less self-contained so it can easily be
- * exported to other applications.
- */
- #include "LogManager.h"
- #include <Packages.h>
- /*
- * There is a 32000 byte maximum for the list, so don't
- * make nLogLines too big.
- */
- #ifndef nDefaultLogLines
- #define nDefaultLogLines 128
- #endif
- #ifndef kScrollBarWidth
- #define kScrollBarWidth 16
- #endif
- #define kCharEllipsis 0xC9 /* ... */
- #define width(r) ((r).right - (r).left)
- #define height(r) ((r).bottom - (r).top)
- #ifndef TRUE
- #define TRUE 1
- #define FALSE 0
- #endif
-
- /*
- * Cheap 'n dirty pascal string copy routine.
- */
- #ifndef pstrcpy
- #define pstrcpy(dst, src) do { \
- StringPtr _src = (src); \
- BlockMove(_src, dst, _src[0] + 1); \
- } while (0)
- #endif
- /*
- * Cheap 'n dirty pascal string concat.
- */
- #ifndef pstrcat
- #define pstrcat(dst, src) do { \
- StringPtr _dst = (dst); \
- StringPtr _src = (src); \
- short _len; \
- _len = 255 - _dst[0]; \
- if (_len > _src[0]) _len = _src[0]; \
- BlockMove(&_src[1], &_dst[1] + _dst[0], _len); \
- _dst[0] += _len; \
- } while (0)
- #endif
-
- static void DrawWideText(
- Ptr textPtr,
- unsigned short offset,
- unsigned short textLength,
- const Rect *boundsRect,
- short textFace
- );
-
-
- /*
- * This record is stored in the userHandle variable in
- * the list. The values are needed to specify the font
- * and limit the number of error log lines that are stored.
- */
- typedef struct LogInfoRecord {
- short logLines;
- short fontNumber;
- short fontSize;
- RGBColor foreColor;
- RGBColor backColor;
- } LogInfoRecord, *LogInfoPtr, **LogInfoHdl;
- #define LIST (**logListHandle)
- #define LOGINFO (**((LogInfoHdl) (LIST.userHandle)))
- #define IS_COLOR(port) (((((CGrafPtr) (port))->portVersion) & 0xC000) != 0)
- #define COLOR_LIST (IS_COLOR(LIST.port))
- /*
- * This code sequence is copied into the ListProc handle. It
- * is designed so we don't have to flush the instruction
- * and data caches.
- */
- static const short gDummyLDEF[] = {
- 0x207A, /* movea.l procPtr,a0 */
- 0x0004, /* <offset to procPtr> */
- 0x4ED0, /* jmp a0 */
- 0x0000, 0x0000 /* dc.l <Drawing Proc here> */
- };
-
- static pascal void
- LogListDefProc(
- short listMessage,
- Boolean listSelect,
- Rect *listRect,
- Cell listCell,
- short listDataOffset,
- short listDataLen,
- ListHandle errorLogList
- );
-
- /*
- * Create the data display list.
- */
- ListHandle
- CreateLog(
- const Rect *viewRect,
- short listFontNumber,
- short listFontSize,
- short logLines
- )
- {
- OSErr status;
- ListHandle logListHandle;
- FontInfo info;
- Point cellSize;
- short listHeight;
- Rect dataBounds;
- Rect listRect;
- short listFontHeight;
- Handle drawProcHdl;
- LogInfoRecord logInfo;
- Handle logInfoHdl;
- ProcPtr listProcPtr;
-
- if (logLines == 0)
- logLines = nDefaultLogLines;
- TextFont(listFontNumber);
- TextSize(listFontSize);
- GetFontInfo(&info);
- listFontHeight = info.ascent + info.descent + info.leading;
- /*
- * Compute the list drawing area, adjusting the list
- * area height so an integral number of lines will be drawn.
- */
- listRect = *viewRect;
- listRect.right -= (kScrollBarWidth - 1);
- listHeight = height(listRect);
- listHeight -= (listHeight % listFontHeight);
- listRect.bottom = listRect.top + listHeight;
- SetPt(&cellSize, width(listRect), listFontHeight);
- /*
- * Create a one-column list.
- */
- SetRect(&dataBounds, 0, 0, 1, 0);
- logInfoHdl = NULL;
- drawProcHdl = NULL;
- logListHandle = LNew(
- &listRect, /* Viewing area */
- &dataBounds, /* Rows and col's */
- cellSize, /* Element size */
- 0, /* No defProc yet */
- qd.thePort, /* Display window */
- TRUE, /* Draw it */
- FALSE, /* No grow box */
- FALSE, /* No horiz scroll */
- TRUE /* Vertical scroll */
- );
- if (logListHandle == NULL)
- goto failure;
- LIST.selFlags = lOnlyOne;
- LIST.listFlags = lDoVAutoscroll;
- logInfo.logLines = logLines;
- logInfo.fontNumber = listFontNumber;
- logInfo.fontSize = listFontSize;
- if (COLOR_LIST) {
- GetForeColor(&logInfo.foreColor);
- GetBackColor(&logInfo.backColor);
- }
- status = PtrToHand(&logInfo, &logInfoHdl, sizeof logInfo);
- if (status != noErr)
- goto failure;
- LIST.userHandle = (Handle) logInfoHdl;
- status = PtrToHand(gDummyLDEF, &drawProcHdl, sizeof gDummyLDEF);
- if (status != noErr)
- goto failure;
- listProcPtr = (ProcPtr) LogListDefProc;
- BlockMove(&listProcPtr, &((short *) *drawProcHdl)[3], sizeof listProcPtr);
- LIST.listDefProc = drawProcHdl;
- goto success;
- failure:
- if (drawProcHdl != NULL)
- DisposeHandle((Handle) drawProcHdl);
- DisposeLog(logListHandle);
- logListHandle = NULL;
- success:
- return (logListHandle);
- }
-
- void
- DisposeLog(
- ListHandle logListHandle
- )
- {
- if (logListHandle != NULL) {
- if (LIST.userHandle != NULL) {
- DisposeHandle(LIST.userHandle);
- LIST.userHandle = NULL;
- }
- LDispose(logListHandle);
- }
- }
-
- void
- UpdateLog(
- ListHandle logListHandle
- )
- {
- Rect viewRect;
- RGBColor saveForeColor;
- RGBColor saveBackColor;
-
- /*
- * Make sure the list is locked down while we draw.
- */
- if (COLOR_LIST) {
- GetForeColor(&saveForeColor);
- GetBackColor(&saveBackColor);
- RGBForeColor(&LOGINFO.foreColor);
- RGBBackColor(&LOGINFO.backColor);
- }
- viewRect = LIST.rView;
- InsetRect(&viewRect, -1, -1);
- EraseRect(&viewRect);
- FrameRect(&viewRect);
- LUpdate(LIST.port->visRgn, logListHandle);
- if (COLOR_LIST) {
- RGBForeColor(&saveForeColor);
- RGBBackColor(&saveBackColor);
- }
- }
-
- void
- ActivateLog(
- ListHandle logListHandle,
- Boolean activating
- )
- {
- LActivate(activating, logListHandle);
- }
-
- void
- MoveLog(
- ListHandle logListHandle,
- short leftEdge,
- short topEdge
- )
- {
- Rect viewRect;
-
- if (LIST.rView.left != leftEdge || LIST.rView.top != topEdge) {
- viewRect = LIST.rView;
- InsetRect(&viewRect, -1, -1);
- InvalRect(&viewRect);
- OffsetRect(
- &LIST.rView,
- leftEdge - LIST.rView.left,
- topEdge -LIST.rView.top
- );
- viewRect = LIST.rView;
- InsetRect(&viewRect, -1, -1);
- InvalRect(&viewRect);
- MoveControl(
- LIST.vScroll,
- LIST.rView.right - (kScrollBarWidth - 1),
- LIST.rView.top - 1
- );
- }
- }
-
- /*
- * SizeLog: this is the true size (we understand scroll bars)
- */
- void
- SizeLog(
- ListHandle logListHandle,
- short newWidth,
- short newHeight
- )
- {
- Rect viewRect;
-
- LSize(newWidth - (kScrollBarWidth - 1), newHeight, logListHandle);
- viewRect = LIST.rView;
- InsetRect(&viewRect, -1, -1);
- InvalRect(&viewRect);
- }
-
- Boolean
- DoClickInLog(
- ListHandle logListHandle,
- const EventRecord *eventRecord
- )
- {
- #define EVENT (*eventRecord)
-
- Point mousePt;
- Boolean result;
- Rect viewRect;
-
- mousePt = EVENT.where;
- GlobalToLocal(&mousePt);
- viewRect = LIST.rView;
- viewRect.right += (kScrollBarWidth - 1);
- if ((result = PtInRect(mousePt, &viewRect)))
- (void) LClick(mousePt, EVENT.modifiers, logListHandle);
- return (result);
- #undef EVENT
- }
-
- /*
- * Log errors.
- */
- void
- LogStatus(
- ListHandle logListHandle,
- OSErr theError,
- const StringPtr infoText
- )
- {
- Str255 msg;
- Str15 errorValue;
-
- if (theError != noErr) {
- pstrcpy(msg, infoText);
- pstrcat(msg, "\p: ");
- NumToString(theError, errorValue);
- pstrcat(msg, errorValue);
- DisplayLogString(logListHandle, msg);
- }
- }
-
- /*
- * DisplayLogString
- * Call this function to store a string in the list.
- */
- void
- DisplayLogString(
- ListHandle logListHandle,
- const StringPtr theString
- )
- {
-
- Cell theCell;
- short theRow;
- Boolean scrollAtBottom;
-
- /*
- * If there are already logLines in the
- * list, delete the first row of the list.
- * Then, in any case, append this datum at the
- * bottom.
- *
- * The scroll bars are managed as follows:
- * scroll bar is at the bottom, the new datum
- * is selected and autoscrolled into view.
- * Otherwise, the current cell is unchanged.
- */
- theRow = LIST.dataBounds.bottom;
- scrollAtBottom =
- (GetCtlValue(LIST.vScroll) == GetCtlMax(LIST.vScroll));
- if (theRow >= LOGINFO.logLines)
- LDelRow(1, 0, logListHandle);
- theRow = LAddRow(1, LIST.dataBounds.bottom, logListHandle);
- if (MemError() != noErr)
- goto failure;
- theCell.h = 0;
- theCell.v = theRow;
- LSetCell((Ptr) &theString[1], theString[0], theCell, logListHandle);
- if (MemError() != noErr)
- goto failure;
- if (scrollAtBottom) {
- theCell.v = 0;
- if (LGetSelect(TRUE, &theCell, logListHandle))
- LSetSelect(FALSE, theCell, logListHandle);
- theCell.v = theRow;
- LSetSelect(TRUE, theCell, logListHandle);
- LDoDraw(TRUE, logListHandle);
- LAutoScroll(logListHandle);
- }
- LDraw(theCell, logListHandle);
- failure:
- return;
- }
-
- /*
- * Draw the string stored in the list. The only difference between this function
- * and a "normal" LDEF is that we don't visually indicate selection. Also, we use
- * the "wide string" scrunchable string drawing procedure.
- */
- static pascal void
- LogListDefProc(
- short listMessage,
- Boolean listSelect,
- Rect *listRect,
- Cell listCell,
- short listDataOffset,
- short listDataLen,
- ListHandle logListHandle
- )
- {
- #pragma unused (listCell)
-
- Boolean cellLockState;
- Rect viewRect;
- RGBColor saveForeColor;
- RGBColor saveBackColor;
-
- /*
- * If the userHandle isn't setup, do nothing: this is an initialization
- * or a spurious command while we're disposing of the list.
- */
- if (LIST.userHandle != NULL) {
- TextFont(LOGINFO.fontNumber);
- TextSize(LOGINFO.fontSize);
- if (COLOR_LIST) {
- GetForeColor(&saveForeColor);
- GetBackColor(&saveBackColor);
- RGBForeColor(&LOGINFO.foreColor);
- RGBBackColor(&LOGINFO.backColor);
- }
- switch (listMessage) {
- case lInitMsg:
- break;
- case lDrawMsg:
- EraseRect(listRect);
- if (listDataLen > 0) {
- viewRect = *listRect;
- viewRect.left += LIST.indent.h;
- /*
- * We don't indent in the vertical direction: by default,
- * it contains the font ascent which is only useful
- * for MoveTo... DrawString drawing.
- */
- cellLockState = HGetState(LIST.cells);
- HLock(LIST.cells);
- DrawWideText(
- (Ptr) (*LIST.cells),
- listDataOffset,
- listDataLen,
- &viewRect,
- normal
- );
- HSetState(LIST.cells, cellLockState);
- }
- if (listSelect == FALSE)
- break;
- /* Continue to do hilite */
- case lHiliteMsg:
- #if 0 /* Hiliting is disabled */
- #ifdef THINK_C
- HiliteMode &= ~(1 << hiliteBit);
- #else /* MPW */
- *((char *) HiliteMode) &= ~(1 << hiliteBit); /* Inside Mac V-61 */
- #endif
- InvertRect(listRect);
- #endif
- break;
- }
- if (COLOR_LIST) {
- RGBForeColor(&saveForeColor);
- RGBBackColor(&saveBackColor);
- }
- }
- }
-
- /*
- * DrawWideText
- * Draw the text within the alloted space. First try "full
- * width", then "condensed", then shrink the and append '...'
- */
- static void
- DrawWideText(
- Ptr textPtr,
- unsigned short offset,
- unsigned short textLength,
- const Rect *boundsRect,
- short textFace
- )
- {
- short oldFace;
- Boolean needEllipsis;
- Ptr theTextPtr;
- short fieldWidth;
- FontInfo fontInfo;
-
- if (textPtr == NULL) {
- textPtr = (Ptr) "<null>";
- offset = 0;
- textLength = 6;
- }
- if (textLength < 0 || textLength > 256) {
- /*
- * This is probably a bug.
- */
- textLength = 256;
- }
- /*
- * It would be more elegant to erase only the area to the right of the
- * text, but that * gets rather messy if we have to deal with ellipses.
- */
- EraseRect(boundsRect);
- fieldWidth = width(*boundsRect);
- theTextPtr = &textPtr[offset];
- oldFace = (*qd.thePort).txFace;
- TextFace(textFace);
- needEllipsis = FALSE;
- if (TextWidth(theTextPtr, 0, textLength) > fieldWidth) {
- TextFace(textFace | condense);
- if (TextWidth(theTextPtr, 0, textLength) > fieldWidth) {
- fieldWidth -= CharWidth(kCharEllipsis);
- needEllipsis = TRUE;
- while (textLength > 1
- && TextWidth(theTextPtr, 0, textLength) > fieldWidth)
- --textLength;
- }
- }
- GetFontInfo(&fontInfo);
- EraseRect(boundsRect);
- MoveTo(boundsRect->left, boundsRect->top + fontInfo.ascent);
- DrawText(theTextPtr, 0, textLength);
- if (needEllipsis)
- DrawChar(kCharEllipsis);
- TextFace(oldFace);
- }
-
-